package com.wei.czz.framework.admin.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wei.czz.common.constant.RedisConstant;
import com.wei.czz.common.enums.CommonEnum;
import com.wei.czz.common.dto.admin.PoetryDto;
import com.wei.czz.common.enums.ResultEnum;
import com.wei.czz.common.exception.CzzException;
import com.wei.czz.common.tool.PageDto;
import com.wei.czz.common.utils.RandomNumUtils;
import com.wei.czz.common.utils.SecurityUtils;
import com.wei.czz.framework.common.handler.redis.RedisHashHandler;
import com.wei.czz.framework.common.handler.redis.RedisStringHandler;
import com.wei.czz.framework.common.handler.redis.RedisHandler;
import com.wei.czz.common.vo.common.PoetryVo;
import com.wei.czz.framework.admin.dao.PoetryDao;
import com.wei.czz.framework.admin.entity.PoetryEntity;
import com.wei.czz.framework.admin.service.PoetryService;
import lombok.AllArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wei
 * date: 2021-06-07 15:56:00
 * className: PoetryServiceImpl 用户诗意文字操作请求服务接口实现类
 * version: 1.0
 * description:
 */
@Service("poetryService")
@AllArgsConstructor
public class PoetryServiceImpl extends ServiceImpl<PoetryDao, PoetryEntity> implements PoetryService {

    private static final Logger log = LoggerFactory.getLogger(PoetryServiceImpl.class);

    private final RedisHashHandler redisHashHandler;

    private final RedisStringHandler redisStringHandler;

    private final RedisHandler redisHandler;

    @Transactional
    @Override
    public void savePoetry(PoetryVo poetryVo) {
        // 获取正在保存自己诗意文字信息的用户id
        Long optUserId = SecurityUtils.getUserId();

        Date date = new Date();

        PoetryEntity poetry = new PoetryEntity();
        // 设置用户id、文字标题、显示方式、是否使用、文字列宁、更新时间和创建时间
        poetry.setUserId(optUserId)
                .setTitle(poetryVo.getTitle())
                .setVertical(poetryVo.getVertical())
                .setUseFlag(poetryVo.getUseFlag())
                .setDataList(JSON.toJSONString(poetryVo.getDataList()))
                .setUpdateTime(date)
                .setCreateTime(date);
        // 操作数据库用户诗意信息表，添加一条用户诗意信息数据
        int count = baseMapper.insert(poetry);
        if (count == 0) {
            throw new CzzException("保存用户诗意信息失败，请联系管理员处理！");
        }

        if (poetryVo.getUseFlag().equals(CommonEnum.ZERO.getValue())) {
            /*
                如果新增的用户诗意信息是立即使用的话
             */
            LambdaQueryWrapper<PoetryEntity> poetryLambdaWrapper = new LambdaQueryWrapper<>();
            // 查询 主键 字段
            poetryLambdaWrapper.select(PoetryEntity::getPoetryId);
            // 匹配用户id和是否使用诗意信息字段
            poetryLambdaWrapper.eq(PoetryEntity::getUserId, optUserId)
                    .eq(PoetryEntity::getUseFlag, CommonEnum.ZERO.getValue());
            // 查询数据库用户诗意信息表，获取用户已使用的诗意信息
            List<PoetryEntity> poetryList = this.list(poetryLambdaWrapper);
            if (!poetryList.isEmpty()) {
                if (poetryList.size() > 1) {
                     log.warn("用户同时存在两个使用中的诗意文字，请务必及时处理。userId={} {}", optUserId, poetryList);
                }
                PoetryEntity poetryEntity = poetryList.get(0);
                if (!poetryEntity.getPoetryId().equals(poetry.getPoetryId())) {
                    poetryEntity.setUseFlag(CommonEnum.ONE.getValue());
                    // 操作数据库用户诗意信息表，取消用户原来使用的诗意信息
                    count = baseMapper.updateById(poetryEntity);
                    if (count == 0) {
                        throw new CzzException("取消用户原来使用的诗意信息失败，请务必及时处理");
                    }
                }
            }

            // 用户添加并使用诗意信息
            PoetryDto poetryDto = new PoetryDto();
            // 属性值复制
            BeanUtils.copyProperties(poetryVo, poetryDto);
            // 设置诗意信息主键
            poetryDto.setPoetryId(poetry.getPoetryId().toString());
            // 操作Redis缓存，设置用户使用的诗意信息
            redisHashHandler.put(RedisConstant.USING_POETRY_MAP, String.valueOf(optUserId), poetryDto);
        }
        // 操作Redis缓存，清空用户诗意列表信息
        redisHandler.fuzzyDelete(RedisConstant.POETRY_LIST + RedisConstant.SPLIT + optUserId
                + RedisConstant.ASTERISK);
    }

    @Override
    public PageDto<PoetryDto> getPoetryList(Long page, Long limit) {
        // 获取正在执行此操作的用户id
        Long optUserId = SecurityUtils.getUserId();

        String userPoetryListKey = RedisConstant.POETRY_LIST + RedisConstant.SPLIT + optUserId
                + RedisConstant.SPLIT + page + RedisConstant.SPLIT + limit;
        // 查询Redis，获取用户的诗意文字列表
        PageDto<PoetryDto> pageDto = redisStringHandler.get(userPoetryListKey);
        if (pageDto != null) {
            // 操作Redis缓存，尝试更新用户诗意信息列表过期时间
            redisHandler.tryUpdateKeyExpire(userPoetryListKey, 150, RandomNumUtils.random5Minutes(10));
            return pageDto;
        }

        LambdaQueryWrapper<PoetryEntity> poetryLambdaWrapper = new LambdaQueryWrapper<>();
        // 查询 诗意信息主键、空间标题、显示方式、是否使用和文字列表 字段
        poetryLambdaWrapper.select(PoetryEntity::getPoetryId, PoetryEntity::getTitle, PoetryEntity::getVertical,
                PoetryEntity::getUseFlag, PoetryEntity::getDataList);
        // 匹配 用户id 字段，数据列表按创建时间倒叙排序
        poetryLambdaWrapper.eq(PoetryEntity::getUserId, optUserId)
                        .orderByDesc(PoetryEntity::getCreateTime);
        Page<PoetryEntity> poetryPage = new Page<>(page, limit);
        // 查询数据库用户诗意信息表，分页查询用户的诗意信息列表
        this.page(poetryPage, poetryLambdaWrapper);
        // 数据封装
        List<PoetryDto> poetryDtoList = new ArrayList<>();
        for (PoetryEntity poetry : poetryPage.getRecords()) {
            PoetryDto poetryDto = new PoetryDto();
            // 设置用户诗意信息主键、空间标题、显示方式、是否被使用、文字列表字段值
            poetryDto.setPoetryId(poetry.getPoetryId().toString())
                    .setTitle(poetry.getTitle())
                    .setVertical(poetry.getVertical())
                    .setUseFlag(poetry.getUseFlag())
                    .setDataList(JSON.parseArray(poetry.getDataList(), String.class));
            poetryDtoList.add(poetryDto);
        }
        // 封装接口返回结果
        pageDto = new PageDto<>(poetryDtoList, poetryPage.getTotal(), page, limit);

        // 操作Redis缓存，用户诗意信息列表缓存五分钟
        redisStringHandler.set(userPoetryListKey, pageDto, RandomNumUtils.random5Minutes(10), TimeUnit.SECONDS);

        return pageDto;
    }

    @Override
    public PoetryDto getUsePoetryInfo(Long optUserId) {
        // 查询Redis缓存，用户已使用的诗意信息
        PoetryDto poetryDto = redisHashHandler.get(RedisConstant.USING_POETRY_MAP, String.valueOf(optUserId));
        if (poetryDto == null) {
            LambdaQueryWrapper<PoetryEntity> poetryLambdaWrapper = new LambdaQueryWrapper<>();
            // 查询 用户诗意信息的诗意信息主键、空间标题、显示方式、是否被使用和文字列表 字段
            poetryLambdaWrapper.select(PoetryEntity::getPoetryId, PoetryEntity::getTitle, PoetryEntity::getVertical,
                    PoetryEntity::getUseFlag, PoetryEntity::getDataList);
            // 匹配 用户id和是否被使用 字段
            poetryLambdaWrapper.eq(PoetryEntity::getUserId, optUserId)
                    .eq(PoetryEntity::getUseFlag, CommonEnum.ZERO.getValue());
            // 查询数据库用户诗意信息表，获取用户已使用的诗意信息
            List<PoetryEntity> poetryList = this.list(poetryLambdaWrapper);
            if (!poetryList.isEmpty()) {
                if (poetryList.size() > 1) {
                    log.warn("用户同时存在两个使用中的诗意文字，请务必及时处理。userId={} {}", optUserId, poetryList);
                }
                PoetryEntity poetry = poetryList.get(0);

                poetryDto = new PoetryDto();
                // 设置用户诗意信息主键、空间标题、显示方式、是否被使用、文字列表属性值
                poetryDto.setPoetryId(poetry.getPoetryId().toString())
                        .setTitle(poetry.getTitle())
                        .setVertical(poetry.getVertical())
                        .setUseFlag(poetry.getUseFlag())
                        .setDataList(JSON.parseArray(poetry.getDataList(), String.class));
            }
        }
        return poetryDto;
    }

    // 异步执行
    @Async("threadExecutor")
    @Override
    public Future<Boolean> getUseFlagInPoetryOnAsync(Long optUserId) {

        PoetryDto poetryDto = this.getUsePoetryInfo(optUserId);

        return AsyncResult.forValue(poetryDto != null);
    }

    @Transactional
    @Override
    public void updatePoetry(PoetryVo poetryVo) {
        // 查询数据库用户诗意信息表，匹配诗意信息主键关联的用户诗意信息
        PoetryEntity poetry = this.getById(Long.parseLong(poetryVo.getPoetryId()));
        if (poetry == null) {
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "您修改的诗意信息不存在，如有问题，请联系管理员处理。");
        }

        // 获取正在修改自己诗意信息的用户id
        Long optUserId = SecurityUtils.getUserId();

        Date date = new Date();
        // 设置用户诗意信息空间标题、显示方式、文字列表和更新时间属性值
        poetry.setTitle(poetryVo.getTitle())
                .setVertical(poetryVo.getVertical())
                .setDataList(JSON.toJSONString(poetryVo.getDataList()))
                .setUpdateTime(date);
        // 操作数据库用户诗意信息表，更新用户诗意信息
        int count = baseMapper.updateById(poetry);
        if (count == 0) {
            throw new CzzException("用户诗意信息修改失败，请务必及时处理");
        }

        if (poetry.getUseFlag().equals(CommonEnum.ZERO.getValue())) {
            /*
                如果修改的是用户已使用的诗意信息，则更新Redis缓存信息
             */
            PoetryDto poetryDto = new PoetryDto();
            // 属性值复制
            BeanUtils.copyProperties(poetryVo, poetryDto);
            // 操作Redis缓存，设置用户使用的诗意信息
            redisHashHandler.put(RedisConstant.USING_POETRY_MAP, String.valueOf(optUserId), poetryDto);
        }
        // 操作Redis缓存，清空用户诗意列表信息
        redisHandler.fuzzyDelete(RedisConstant.POETRY_LIST + RedisConstant.SPLIT + optUserId
                + RedisConstant.ASTERISK);
    }

    @Transactional
    @Override
    public void usingPoetry(String poetryId) {
        // 获取正在设置自己使用的诗意信息的用户id
        Long optUserId = SecurityUtils.getUserId();
        String userId = String.valueOf(optUserId);

        // 用户诗意信息主键解密
        long lPoetryId = Long.parseLong(poetryId);
        // 查询数据库用户诗意信息表，根据用户诗意主键查询对应诗意信息
        PoetryEntity poetry = this.getById(lPoetryId);
        if (poetry == null) {
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "您设置的诗意信息不存在，如有问题，请联系管理员处理。");
        }

        Date date = new Date();

        int count;
        // 获取用户已使用诗意信息
        PoetryDto poetryDto = this.getUsePoetryInfo(optUserId);
        if (poetryDto != null) {
            if (poetryId.equals(poetryDto.getPoetryId())) {
                throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "您已使用该诗意信息，无需重复设置。");
            }
            // 诗意文字主键解密
            lPoetryId = Long.parseLong(poetryDto.getPoetryId());
            PoetryEntity oldUsePoetry = new PoetryEntity();
            oldUsePoetry.setPoetryId(lPoetryId)
                    .setUseFlag(CommonEnum.ONE.getValue())
                    .setUpdateTime(date);
            // 操作数据库用户诗意信息表，取消原来使用的诗意信息状态
            count = baseMapper.updateById(oldUsePoetry);
            if (count == 0) {
                throw new CzzException("修改用户使用的诗意信息失败，请务必及时处理");
            }
        }

        poetry.setUseFlag(CommonEnum.ZERO.getValue())
                .setUpdateTime(date);
        // 操作数据库用户诗意信息表，更新用户诗意信息
        count = baseMapper.updateById(poetry);
        if (count == 0) {
            throw new CzzException("修改用户使用的诗意信息失败，请务必及时处理");
        }

        poetryDto = new PoetryDto();
        // 设置用户诗意信息主键、空间标题、显示方式、是否被使用、文字列表属性值
        poetryDto.setPoetryId(poetryId)
                .setTitle(poetry.getTitle())
                .setVertical(poetry.getVertical())
                .setUseFlag(poetry.getUseFlag())
                .setDataList(JSON.parseArray(poetry.getDataList(), String.class));
        // 操作Redis缓存，设置用户使用的诗意信息
        redisHashHandler.put(RedisConstant.USING_POETRY_MAP, userId, poetryDto);
        // 操作Redis缓存，清空用户诗意列表信息
        redisHandler.fuzzyDelete(RedisConstant.POETRY_LIST + RedisConstant.SPLIT + userId
                + RedisConstant.ASTERISK);
    }

    @Transactional
    @Override
    public void cancelUsingPoetry(String poetryId) {
        Long poetryId2 = Long.parseLong(poetryId);
        // 查询数据库用户诗意信息表，匹配用户诗意信息主键对应的诗意信息
        PoetryEntity poetry = this.getById(poetryId2);
        if (poetry == null) {
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "您要取消使用的诗意信息不存在，取消操作失败。");
        }

        if (poetry.getUseFlag().equals(CommonEnum.ONE.getValue())) {
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "您没有使用该诗意信息，不能取消使用，取消操作失败。");
        }
        poetry = new PoetryEntity();
        // 设置用户诗意信息主键和是否被使用字段
        poetry.setPoetryId(poetryId2)
                .setUseFlag(CommonEnum.ONE.getValue());
        // 操作数据库用户诗意信息表，用户使用的诗意信息改为不使用
        int count = baseMapper.updateById(poetry);
        if (count == 0) {
            throw new CzzException("取消用户已使用的诗意信息失败，请务必及时处理");
        }

        // 获取正在取消自己使用的诗意文字信息的用户id
        String optUserId = SecurityUtils.getUserId().toString();
        // 操作Redis缓存，删除用户使用的诗意信息缓存
        redisHashHandler.delete(RedisConstant.USING_POETRY_MAP, optUserId);
        // 操作Redis缓存，清空用户诗意列表信息
        redisHandler.fuzzyDelete(RedisConstant.POETRY_LIST + RedisConstant.SPLIT + optUserId
                + RedisConstant.ASTERISK);
    }

    @Transactional
    @Override
    public void deletePoetry(String sPoetryId) {

        long poetryId = Long.parseLong(sPoetryId);
        // 查询数据库用户诗意信息表，获取诗意信息主键对应的诗意信息
        PoetryEntity poetry = this.getById(poetryId);
        if (poetry == null) {
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "您要删除的诗意信息不存在，删除操作失败。");
        }
        // 操作数据库用户诗意信息表，根据诗意信息主键删除诗意信息
        int count = baseMapper.deleteById(poetryId);
        if (count == 0) {
            throw new CzzException("删除用户诗意信息失败，请务必及时处理");
        }
        // 获取正在删除自己的诗意信息的用户id
        String optUserId = SecurityUtils.getUserId().toString();
        if (poetry.getUseFlag().equals(CommonEnum.ZERO.getValue())) {
            // 操作Redis缓存，删除用户使用的诗意信息缓存
            redisHashHandler.delete(RedisConstant.USING_POETRY_MAP, optUserId);
        }
        // 操作Redis缓存，清空用户诗意列表信息
        redisHandler.fuzzyDelete(RedisConstant.POETRY_LIST + RedisConstant.SPLIT + optUserId
                + RedisConstant.ASTERISK);
    }
}
